package net.lesscoding.protocol;

import com.google.gson.Gson;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;
import net.lesscoding.message.Message;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author eleven
 * @date 2024/10/31 8:26
 * @apiNote A Codec for on-the-fly encoding/decoding of bytes to messages and vise-versa.
 * <p>
 * This can be thought of as a combination of {@link ByteToMessageDecoder} and {@link MessageToByteEncoder}.
 * <p>
 * Be aware that sub-classes of {@link ByteToMessageCodec} MUST NOT
 * annotated with {@link @Sharable}.
 */
@Slf4j
public class MessageCodec extends ByteToMessageCodec<Message> {

    private Gson gson = new Gson();

    /**
     * 0. JDK 的序列化方式
     * <pre>
     * ByteArrayOutputStream baos = new ByteArrayOutputStream();
     * ObjectOutputStream oos = new ObjectOutputStream(baos);
     * oos.writeObject(msg);
     * byte[] byteArray = baos.toByteArray();
     * </pre>
     *
     * @param ctx channel上下文
     * @param msg 消息
     * @param out 缓冲区
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        // 1. 8 字节的魔数
        out.writeBytes("AreYouOk".getBytes());
        // 2. 1 字节的版本
        out.writeByte(1);
        // 3. 1 字节的序列化方式 0jdk 1json 2protobuf 3kryo
        out.writeByte(0);
        // 4. 1 字节的指令类型
        out.writeByte(msg.getMessageType());
        // 5. 4 个字节的请求序号
        out.writeInt(msg.getSequenceId());
        // 5.1 无意义字节，让内容前的字节数对接2的整数倍
        out.writeByte(0xff);
        // 6. 正文的长度 JDK序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(msg);
        byte[] bytes = baos.toByteArray();
        //String msgJson = gson.toJson(msg);
        //byte[] bytes = msgJson.getBytes();
        out.writeInt(bytes.length);
        // 7. 正文
        out.writeBytes(bytes);

    }

    /**
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 1. 从头读取八个字节魔数
        byte[] magicByte = new byte[8];
        String magicStr = in.readBytes(magicByte).toString(StandardCharsets.UTF_8);
        // 2. 读取版本
        byte version = in.readByte();
        // 3. 读取序列化方式
        byte serializerType = in.readByte();
        // 4. 读取指令类型
        byte messageType = in.readByte();
        // 5. 读取请求序号
        int sequenceId = in.readInt();
        // 6. 读取无意义字节
        in.readByte();
        // 7. 读取正文长度
        int length = in.readInt();
        // 8. 读取正文
        byte[] bytes = new byte[length];
        in.readBytes(bytes);
        // 9. 反序列化
        Message message = null;
        if (serializerType == 0) {
            // JDK 反序列化
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
            message = (Message) ois.readObject();
        }
        if (serializerType == 1) {
            message = gson.fromJson(new String(bytes), Message.class);
        }
        // 10. 加入到 out 中
        out.add(message);
        // 打印数据
        log.debug("{},{},{},{},{},{}",
                magicStr, version, serializerType, messageType, sequenceId, length);
        log.debug("{}", message);
    }
}
